#include <Arduino.h>
#include <HardwareSerial.h>

#include "Timer.h"
#include "Display.h"
#include "Controls.h"
#include "Controller.h"

Timer timer;
Display display;
Controls controls;
Commander commander;

Cooling cooling(PIN_WATER_COOLER);
Illumination illumination(LINES_COUNT, LINES_PINS);
DallasThermometer thermometer("TW", PIN_WATER_TEMPERATURE, WATER_TEMPERATURE_ADDRESS);

Actuator *const actuators[] = {&display, &thermometer, &illumination, &cooling, &controls};
CommandProcessor *const commandProcessors[] = {&timer, &display, &thermometer, &illumination, &cooling};

const uint8_t actuatorsCount = (uint8_t const) (sizeof(actuators) / sizeof(Actuator));
const uint8_t commandProcessorsCount = (uint8_t const) (sizeof(commandProcessors) / sizeof(CommandProcessor));

String response = String();
error_t lastError = NO_ERROR;

void setupAquaController() {
    Serial.println("Loading controller code...");
    response.reserve(30);

//    unsigned int rndSeed = (unsigned int) analogRead(PIN_SERVICE_RANDOM);
//    Serial.print("Random seed: ");
//    Serial.println(rndSeed);
//    randomSeed(rndSeed);

    Serial.print("Connected actuators: ");
    Serial.println(actuatorsCount);

    if ((lastError = timer.begin()) != NO_ERROR) {
        Serial.print("Timer can't be initialized: ERR");
        Serial.println(lastError);
    }

    for (uint8_t i = 0; i < actuatorsCount; ++i) {
        Actuator *actuator = actuators[i];
        if ((lastError = actuator->begin()) != NO_ERROR) {
            Serial.print("Actuator can't be initialized: ERR");
            Serial.println(lastError);
        }
    }

    if (!lastError) {
        lastError = controls.attachIllumination(illumination);
    }

    if (lastError != NO_ERROR) {
        display.showError(lastError);
    }
    Serial.println("Controller loaded");
}

void loopAquaController() {
    const time_t time = timer.time();
    const tick_t ticks = timer.ticks();

    for (uint8_t i = 0; i < actuatorsCount && lastError == NO_ERROR; ++i) {
        Actuator *actuator = actuators[i];
        if ((lastError = actuator->tick(ticks, time)) != NO_ERROR) {
            Serial.print("Actuator can't be processed: ERR");
            Serial.println(lastError);
        }
    }

#ifndef DISABLE_COMMANDS_PROCESSOR
    String const *request = commander.readRequest();
    if (request != NULL) {
        for (int i = 0; i < commandProcessorsCount; ++i) {
            response = "";
            CommandProcessor *processor = commandProcessors[i];
            if (processor->isSupported(*request)) {
                error_t err = processor->processCommand(*request, response);
                if (err != NO_ERROR) {
                    commander.writeResponse(err);
                } else {
                    commander.writeResponse(response);
                }
            }
        }
    }
#endif

    display.validate(timer, illumination, thermometer, cooling);
}
